#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <linux/input.h>

#define JOYPAD_DEV "/dev/joypad"
// #define USB_JS_DEV "/dev/input/js0"
#define USB_JS_DEV "/dev/input/event3"
// #define USB_JS_DEV "/dev/input/event4"

#define KB_JS_DEV "/dev/input/event3"
#define KB_JS_DEV "/dev/input/event8"


typedef struct JoypadInput{
	int (*DevInit)(void);
	int (*DevExit)(void);
	int (*GetJoypad)(void);
	struct JoypadInput *ptNext;
	pthread_t tTreadID;     /* 子线程ID */
}T_JoypadInput, *PT_JoypadInput;

struct js_event {		
	unsigned int   time;      /* event timestamp in milliseconds */		
	unsigned short value;     /* value */		
	unsigned char  type;      /* event type */		
	unsigned char  number;    /* axis/button number */	
};

//全局变量通过互斥体访问
static unsigned char g_InputEvent;

static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;

static int joypad_fd;
static int USBjoypad_fd;
static int KBjoypad_fd;
static PT_JoypadInput g_ptJoypadInputHead;


static void *InputEventTreadFunction(void *pVoid)
{
	/* 定义函数指针 */
	int (*GetJoypad)(void);
	GetJoypad = (int (*)(void))pVoid;

	while (1)
	{
		//因为有阻塞所以没有输入时是休眠
		g_InputEvent = GetJoypad();
		//有数据时唤醒
		pthread_mutex_lock(&g_tMutex);
		/*  唤醒主线程 */
		pthread_cond_signal(&g_tConVar);
		pthread_mutex_unlock(&g_tMutex);
	}
}

static int RegisterJoypadInput(PT_JoypadInput ptJoypadInput)
{
	PT_JoypadInput tmp;
	if(ptJoypadInput->DevInit())
	{
		return -1;
	}
	//初始化成功创建子线程 将子项的GetInputEvent 传进来
	pthread_create(&ptJoypadInput->tTreadID, NULL, InputEventTreadFunction, (void*)ptJoypadInput->GetJoypad);
	if(! g_ptJoypadInputHead)
	{
		g_ptJoypadInputHead = ptJoypadInput;
	}
	else
	{
		tmp = g_ptJoypadInputHead;
		while(tmp->ptNext)
		{
			tmp = tmp->ptNext;
		}
		tmp->ptNext = ptJoypadInput;
	}
	ptJoypadInput->ptNext = NULL;
	return 0;
}

static int joypadGet(void)
{
	static unsigned char joypad = 0;
	//printf("joypadGet val:\n");
	joypad = read(joypad_fd, 0, 0);
	return joypad;
}

static int joypadDevInit(void)
{
	joypad_fd = open(JOYPAD_DEV, O_RDONLY);
	if(-1 == joypad_fd)
	{
		printf("JOYPAD_DEV %s dev not found \r\n", JOYPAD_DEV);
		return -1;
	}
	return 0;
}

static int joypadDevExit(void)
{
	close(joypad_fd);
	return 0;
}

static T_JoypadInput joypadInput = {
	joypadDevInit,
	joypadDevExit,
	joypadGet,
};

static int USBjoypadGet(void)
{
	/**
	 * FC手柄 bit 键位对应关系 真实手柄中有一个定时器，处理 连A  连B 
	 * 0  1   2       3       4    5      6     7
	 * A  B   Select  Start  Up   Down   Left  Right
	 */
	//因为 USB 手柄每次只能读到一位键值 所以要有静态变量保存上一次的值
	static unsigned char joypad = 0;
	struct js_event e;
	// printf("%s\r\n", __FUNCTION__);
	if(0 < read (USBjoypad_fd, &e, sizeof(e)))
	{
		if(0x2 == e.type)
		{
            printf("value %x\r\n", e.value);
			/*
			上：
			value:0x8001 type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x8001 == e.value && 0x5 == e.number)
			{
				joypad |= 1<<4;
			}
			
			/*下：
			value:0x7fff type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x7fff == e.value && 0x5 == e.number)
			{
				joypad |= 1<<5;
			}
			//松开
			if(0x0 == e.value && 0x5 == e.number)
			{
				joypad &= ~(1<<4 | 1<<5);
			}
			
			/*左：
			value:0x8001 type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x8001 == e.value && 0x4 == e.number)
			{
				joypad |= 1<<6;
			}
			
			/*右：
			value:0x7fff type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x7fff == e.value && 0x4 == e.number)
			{
				joypad |= 1<<7;
			}
			//松开
			if(0x0 == e.value && 0x4 == e.number)
			{
				joypad &= ~(1<<6 | 1<<7);
			}
		}

		if(0x1 == e.type)
		{
			/*选择：
			value:0x1 type:0x1 number:0xa
			value:0x0 type:0x1 number:0xa
			*/
			if(0x1 == e.value && 0xa == e.number)
			{
				joypad |= 1<<2;
			}
			if(0x0 == e.value && 0xa == e.number)
			{
				joypad &= ~(1<<2);
			}
			
			/*开始：
			value:0x1 type:0x1 number:0xb
			value:0x0 type:0x1 number:0xb
			*/
			if(0x1 == e.value && 0xb == e.number)
			{
				joypad |= 1<<3;
			}
			if(0x0 == e.value && 0xb == e.number)
			{
				joypad &= ~(1<<3);
			}

			/*A
			value:0x1 type:0x1 number:0x0
			value:0x0 type:0x1 number:0x0
			*/
			if(0x1 == e.value && 0x0 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x0 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*B
			value:0x1 type:0x1 number:0x1
			value:0x0 type:0x1 number:0x1
			*/
			if(0x1 == e.value && 0x1 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x1 == e.number)
			{
				joypad &= ~(1<<1);
			}

			/*X
			value:0x1 type:0x1 number:0x3
			value:0x0 type:0x1 number:0x3
			*/
			if(0x1 == e.value && 0x3 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x3 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*Y
			value:0x1 type:0x1 number:0x4
			value:0x0 type:0x1 number:0x4
		 	*/
		 	if(0x1 == e.value && 0x4 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x4 == e.number)
			{
				joypad &= ~(1<<1);
			}
		}
		return joypad;
	}
	return -1;
}

static int USBjoypadDevInit(void)
{
	USBjoypad_fd = open(USB_JS_DEV, O_RDONLY);
	if(-1 == USBjoypad_fd)
	{
		printf("USB_JS_DEV %s dev not found \r\n", USB_JS_DEV);
		return -1;
	}
	return 0;
}

static int USBjoypadDevExit(void)
{
	close(USBjoypad_fd);
	return 0;
}

static T_JoypadInput usbJoypadInput = {
	USBjoypadDevInit,
	USBjoypadDevExit,
	USBjoypadGet,
};

static int KBjoypadDevInit(void)
{
    char *env = getenv("DEVICE_JS_DEV");
    printf("eve %s\r\n", env);
    if (env == NULL) {
        env = KB_JS_DEV;
    }
	KBjoypad_fd = open(env, O_RDONLY);
	if(-1 == KBjoypad_fd)
	{
		printf("USB_JS_DEV %s dev not found \r\n", USB_JS_DEV);
		return -1;
	}
	return 0;
}
static int KBjoypadDevExit(void)
{
	close(KBjoypad_fd);
	return 0;
}
static int KBjoypadGet(void)
{
    struct input_event event_status;
	static unsigned char joypad = 0;
    int   len              = 0;
    len = read(KBjoypad_fd, &event_status, sizeof(event_status));
	// printf("%s\r\n", __FUNCTION__);
     #define JOY_A       (1 << 1)
    #define JOY_B       (1 << 0)
    #define JOY_SELECT  (1 << 2)
    #define JOY_START   (1 << 3)
    #define JOY_UP      (1 << 4)
    #define JOY_DOWN    (1 << 5)
    #define JOY_LEFT    (1 << 6)
    #define JOY_RIGHT   (1 << 7)

#if 1
	#define CODE_L KEY_A
	#define CODE_R KEY_D
	#define CODE_U KEY_W
	#define CODE_D KEY_S

#if 1
	#define CODE_A KEY_LEFTSHIFT // KEY_J
	#define CODE_B KEY_SPACE // KEY_K
	#define CODE_START KEY_RIGHTSHIFT //KEY_SPACE
	#define CODE_SELECT KEY_ENTER
#else  // 双手
	#define CODE_A KEY_J
	#define CODE_B KEY_K
	#define CODE_START KEY_SPACE
	#define CODE_SELECT KEY_ENTER
#endif
#else
	#define CODE_L 0x126
	#define CODE_R 0x124
	#define CODE_U 0x127
	#define CODE_D 0x125

	#define CODE_A 0x123
	#define CODE_B 0x122
	#define CODE_START 0x120
	#define CODE_SELECT 0x121
#endif

	// EV_ABS
	/*
	              type code value
	X Left press     3     0   0xff
	X Right press    3     0   0x0
	X release        3     0   0x7f
	*/

	if (event_status.type == EV_ABS) {
		if (event_status.code == ABS_X) {
			switch (event_status.value)
			{
			case 0xff:
				joypad |= JOY_RIGHT;
				break;
			case 0:
				joypad |= JOY_LEFT;
				break;
			case 0x7f:
				joypad &= ~(JOY_LEFT | JOY_RIGHT);
				break;
			default:
				printf("没有处理模拟量 %x\r\n", event_status.value);
				break;
			}
		}

		if (event_status.code == ABS_Y) {
			switch (event_status.value)
			{
			case 0xff:
				joypad |= JOY_DOWN;
				break;
			case 0:
				joypad |= JOY_UP;
				break;
			case 0x7f:
				joypad &= ~(JOY_DOWN | JOY_UP);
				break;
			default:
				printf("没有处理模拟量 %x\r\n", event_status.value);
				break;
			}
		}
	}


	// EV_KEY
    if (event_status.value == 1 || event_status.value == 2) {
        switch(event_status.code) {
        case CODE_SELECT://KEY_F3:// SELECT
            joypad |= JOY_SELECT;
            break;
        case CODE_START://KEY_F5:// START
            joypad |= JOY_START;
            break;
        case CODE_A: //KEY_LEFTSHIFT:// A
            joypad |= JOY_A;
            break;
        case CODE_B: //KEY_SPACE:// B
            joypad |= JOY_B;
            break;

        // case KEY_LEFT:
        //     joypad |= JOY_LEFT;
        //     break;
        // case KEY_RIGHT:
        //     joypad |= JOY_RIGHT;
        //     break;
        // case KEY_UP:
        //     joypad |= JOY_UP;
        //     break;
        // case KEY_DOWN:
        //     joypad |= JOY_DOWN;
        //     break;

        case CODE_L:
            joypad |= JOY_LEFT;
            break;
        case CODE_R:
            joypad |= JOY_RIGHT;
            break;
        case CODE_U:
            joypad |= JOY_UP;
            break;
        case CODE_D:
            joypad |= JOY_DOWN;
            break;

        }
    }


    if (event_status.value == 0) {
        switch(event_status.code) {
        case CODE_SELECT:// SELECT
            joypad &= ~JOY_SELECT;
            break;
        case CODE_START:// START
            joypad &= ~JOY_START;
            break;
        case CODE_A:// A
            joypad &= ~JOY_A;
            break;
        case CODE_B:// B
            joypad &= ~JOY_B;
            break;
        // case KEY_LEFT:
        //     joypad &= ~JOY_LEFT;
        //     break;
        // case KEY_RIGHT:
        //     joypad &= ~JOY_RIGHT;
        //     break;
        // case KEY_UP:
        //     joypad &= ~JOY_UP;
        //     break;
        // case KEY_DOWN:
        //     joypad &= ~JOY_DOWN;
        //     break;
        case CODE_L:
            joypad &= ~JOY_LEFT;
            break;
        case CODE_R:
            joypad &= ~JOY_RIGHT;
            break;
        case CODE_U:
            joypad &= ~JOY_UP;
            break;
        case CODE_D:
            joypad &= ~JOY_DOWN;
            break;
        }
    }
    return joypad;
}
static T_JoypadInput kbJoypadInput = {
	KBjoypadDevInit,
	KBjoypadDevExit,
	KBjoypadGet,
};

int InitJoypadInput(void)
{
	int iErr = 0;
	// iErr = RegisterJoypadInput(&joypadInput);
	// iErr = RegisterJoypadInput(&usbJoypadInput);
    iErr = RegisterJoypadInput(&kbJoypadInput);
	return iErr;
}

int GetJoypadInput(void)
{
    #if 0
	/* 休眠 */
	pthread_mutex_lock(&g_tMutex);
	pthread_cond_wait(&g_tConVar, &g_tMutex);	

	/* 被唤醒后,返回数据 */
	pthread_mutex_unlock(&g_tMutex);
    #else
    // static int times = 0;
    // if (times++ >= 1) {
    //     g_InputEvent = (1 << 3);
    //     times = 0;
    // }
    // else {
    //     g_InputEvent = 0;
    // }
    
    #endif
    // printf("g_InputEvent %x\r\n", g_InputEvent);
	return g_InputEvent;
}




